package com.wanhugou.payment.controller;

import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.math.BigDecimal;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import me.chanjar.weixin.common.util.RandomUtils;
import net.sf.json.JSONObject;

import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import com.lijing.wechatpay.impl.PayImpl;
import com.wanhugou.payment.config.WechatConfig;
import com.wanhugou.payment.domain.PayBizStatusEnum;
import com.wanhugou.payment.domain.PayLog;
import com.wanhugou.payment.domain.PayRecordVo;
import com.wanhugou.payment.domain.PayTypeEnum;
import com.wanhugou.payment.domain.RecordTypeEnum;
import com.wanhugou.payment.domain.UnifiedOrderResult;
import com.wanhugou.payment.service.PayLogService;
import com.wanhugou.payment.util.MapUtils;
import com.wanhugou.payment.util.ParamUtils;
import com.wanhugou.payment.util.PayCommonUtil;
import com.wanhugou.payment.util.ResultData;
import com.wanhugou.payment.util.XMLUtil;

@RestController
@RequestMapping("wx")
public class WechatPayAction {

	private final Logger log = LoggerFactory.getLogger(WechatPayAction.class);
	@Value("${WX_REQ_URL}")
	private String req_URL;
	@Value("${WALLET_URL}")
	private String wallet;
	@Value("${WX_TRANSFER}")
	private String transferURL;

	@Autowired
	private WechatConfig wxchatConfig;
	@Autowired
	private PayLogService payLogService;
	@Autowired
	private RestTemplate restTemplate;

	/**
	 * <p>
	 * Description: TODO(APP调起微信支付)</br>
	 * 
	 * @author liyd
	 * @param u
	 * @return
	 */
	@RequestMapping(value = "appPay", method = RequestMethod.GET)
	public ResultData<Map<String, Object>> appPay(HttpServletResponse response,
			HttpServletRequest request,
			@RequestParam("out_trade_no") String out_trade_no,
			@RequestParam("amount") double amount,
			@RequestParam("custId") Integer custId,
			@RequestParam("payer") Integer payer) {
		log.info("APP调起微信支付");
		ResultData<Map<String, Object>> data = new ResultData<Map<String, Object>>();
		try {
			PayLog pay = new PayLog();
			String ip = request.getRemoteHost();
			pay.setRemark(ip);
			pay.setOut_trade_no(out_trade_no);
			pay.setAmount(String.valueOf(amount));
			pay.setCustId(custId);
			pay.setPayer(payer);
			log.info("请求参数：" + JSONObject.fromObject(pay));
			Map<String, Object> map = commitOrder(pay);
			if (map.containsKey("return_msg")) {
				data.setStatus(data.STATUS_ERROR);
			} else {
				data.setStatus(data.STATUS_NORMAL);
			}
			data.setData(map);
		} catch (Exception e1) {
			log.error("请求调用失败---" + e1.getMessage().toString());
			data.setStatus(data.STATUS_ERROR);
			data.setMessage(e1.getMessage());
		}
		return data;
	}

	@RequestMapping(value = "transfer", method = RequestMethod.GET)
	public ResultData<PayRecordVo> transfer(
			@RequestParam("out_trade_no") String out_trade_no,
			@RequestParam("amount") double amount,
			@RequestParam("custId") Integer custId,
			@RequestParam("payer") Integer payer,
			@RequestParam("payee_account") String payee_account,
			HttpServletRequest request) {
		ResultData<PayRecordVo> data = new ResultData<PayRecordVo>();
		log.info("------微信提现-----");
		try {
			PayLog pay = new PayLog();
			String ip = request.getRemoteHost();
			pay.setOut_trade_no(out_trade_no);
			pay.setAmount(String.valueOf(amount));
			pay.setCustId(custId);
			pay.setPayer(payer);
			pay.setPayee_account(payee_account);
			SortedMap<String, Object> map = new TreeMap<String, Object>();
			String nonceStr = RandomUtils.getRandomStr();
			int money = (int) (Double.valueOf(pay.getAmount()) * 100);
			map.put("mch_appid", wxchatConfig.getMchappid());
			map.put("mchid", wxchatConfig.getMchID());
			// map.put("mchid", 1482138712);
			map.put("nonce_str", nonceStr);
			map.put("partner_trade_no", pay.getOut_trade_no());
			map.put("openid", pay.getPayee_account());
			map.put("check_name", "NO_CHECK");
			map.put("amount", String.valueOf(money));
			map.put("desc", "提现");
			map.put("spbill_create_ip", ip);
			SortedMap<String, Object> sortMap = MapUtils.sortMap(map);
			String sign = PayCommonUtil.createSign("UTF-8", sortMap,
					wxchatConfig.getMchKey());
			map.put("sign", sign);
			
			log.info("----添加充值记录");
			pay.setPlatform("w");
			pay.setPay_type("d");
			pay.setBiz_status(PayBizStatusEnum.BIZ_STATUS_B.getCode());
			payLogService.insert(pay);
			String requestXml = PayCommonUtil.getRequestXml(map);
			log.info("----微信提现请求参数" + requestXml);
			String resXml = restTemplate.postForObject(transferURL, requestXml,
					String.class);
			log.info("----微信提现返回参数" + resXml);
			SortedMap<Object, Object> resMap = XMLUtil.doXMLParse(resXml);
			if (StringUtils.equals("SUCCESS", resMap.get("return_code")
					.toString())
					&& StringUtils.equals("SUCCESS", resMap.get("result_code")
							.toString())) {
				log.info("修改充值记录");
				PayLog transfer = new PayLog();
				transfer.setOut_trade_no(map.get("partner_trade_no").toString());
				transfer.setBiz_status(PayBizStatusEnum.BIZ_STATUS_C.getCode());
				payLogService.update(transfer );
				PayRecordVo vo = new PayRecordVo();
				vo.setOutTradeNo(resMap.get("payment_no").toString());
				vo.setPayNum(map.get("partner_trade_no").toString());
				vo.setAccount(resMap.get("mchid").toString());
				vo.setAmount(Double.valueOf(pay.getAmount()) / 100);
				vo.setPayType(PayTypeEnum.PAY_WX.getCode());
				vo.setRecordType(RecordTypeEnum.WITHDRAWALS.getCode());
				data.setData(vo);
				data.setStatus(data.STATUS_NORMAL);
				log.info("微信提现成功");
			} else {
				data.setStatus(data.STATUS_ERROR);
				log.info("微信提现失败");
			}
		} catch (Exception e) {
			e.printStackTrace();
			log.error("提现失败：" + e.getMessage());
			data.setStatus(data.STATUS_ERROR);
		}
		return data;
	}

	/**
	 * 
	 * <p>
	 * Description: TODO(微信通知支付结果的回调地址)</br>
	 * 
	 * @author liyd
	 * @param request
	 * @param response
	 */
	@RequestMapping("wxnotify")
	public void wxnotify(HttpServletRequest request,
			HttpServletResponse response) {
		log.info("----------微信支付回调通知-----------");
		try {
			SortedMap<Object, Object> sort = getResult(request);
			log.info("微信返回结果集:" + sort);
			String resXml = null;
			if ("SUCCESS".equals((String) sort.get("return_code"))) {
				if (PayCommonUtil.isTenpaySign("UTF-8", sort,
						wxchatConfig.getMchKey())) {
					resXml = PayCommonUtil.returnResXml("SUCCESS", "回调成功");
					String out_trade_no = (String) sort.get("out_trade_no");
					// 添加支付记录
					String selectByNo = payLogService.selectByNo(out_trade_no);
					if (StringUtils.isNotBlank(selectByNo)) {
						PayLog pay = new PayLog();
						pay.setOut_trade_no(out_trade_no);
						pay.setBiz_status(PayBizStatusEnum.BIZ_STATUS_C.getCode());
						payLogService.update(pay);
						updatePaylog(sort);
					}
					log.info("回调成功");
				} else {
					resXml = PayCommonUtil.returnResXml("FAIL", "签名错误");
					log.info("签名错误");
				}
			} else {
				log.info("回调失败");
				resXml = PayCommonUtil.returnResXml("FAIL", "回调失败");
			}
			log.info("报文：" + resXml);
			BufferedOutputStream out = new BufferedOutputStream(
					response.getOutputStream());
			out.write(resXml.getBytes());
			out.flush();
			out.close();
		} catch (Exception e) {
			log.error(e.getMessage());
			e.printStackTrace();
		}
	}

	/**
	 * <p>
	 * Description: TODO(统一下单并返回前台调用微信需要参数)</br>
	 * 
	 * @author liyd
	 * @param unifiedOrder
	 * @return
	 */
	private Map<String, Object> commitOrder(PayLog pay) {
		String reqXML = getResXML(pay);
		String respXML = PayImpl.requestWechat(req_URL, reqXML);
		UnifiedOrderResult uor = (UnifiedOrderResult) PayImpl.turnObject(
				UnifiedOrderResult.class, respXML);
		Map<String, Object> map = RespMap(uor);
		return map;
	}

	/**
	 * <p>
	 * Description: TODO(组装订单)</br>
	 * 
	 * @author liyd
	 * @param u
	 * @return
	 */
	private String getResXML(PayLog pay) {
		String total_fee = new BigDecimal(pay.getAmount())
				.multiply(new BigDecimal(100)).toBigInteger().toString();// 放大一百倍
		String nonceStr = RandomUtils.getRandomStr();
		SortedMap<String, Object> oparams = new TreeMap<String, Object>();
		oparams.put("appid", wxchatConfig.getAppid());// 服务号的应用号
		oparams.put("body", "采购商APP-钱包充值");// 商品描述
		oparams.put("mch_id", wxchatConfig.getMchID());// 商户号 ？
		oparams.put("nonce_str", nonceStr);// 16随机字符串(大小写字母加数字)
		oparams.put("out_trade_no", pay.getOut_trade_no());// 商户订单号
		oparams.put("total_fee", total_fee);
		oparams.put("spbill_create_ip", pay.getRemark());// IP地址
		oparams.put("notify_url", wxchatConfig.getNotifyURL()); // 微信回调地址
		oparams.put("trade_type", "APP");// 支付类型 app
		String param = ParamUtils.getParam(pay);
		oparams.put("attach", param);// 支付类型 app
		SortedMap<String, Object> sortMap = MapUtils.sortMap(oparams);
		String sign = PayCommonUtil.getSign(sortMap, wxchatConfig.getMchKey());
		oparams.put("sign", sign);
		String resXml = PayCommonUtil.getResXml(oparams);
		log.info("----添加支付记录");
		pay.setPay_type("a");
		pay.setPlatform("w");
		pay.setBiz_status(PayBizStatusEnum.BIZ_STATUS_B.getCode());
		pay.setRemark("微信支付");
		pay.setCreate_time(new Date());
		payLogService.insert(pay);
		return resXml;
	}

	/**
	 * <p>
	 * Description: TODO(返回前端调微信需要的参数)</br>
	 * 
	 * @author liyd
	 * @param uor
	 * @return
	 */
	private Map<String, Object> RespMap(UnifiedOrderResult uor) {
		Map<String, Object> map = new HashMap<String, Object>();
		if (StringUtils.isNotBlank(uor.getPrepay_id())) {
			// 调起支付所需参数和签名
			long timestamp = System.currentTimeMillis() / 1000;
			String randomStr = RandomUtils.getRandomStr();
			SortedMap<String, Object> parameters = new TreeMap<String, Object>();
			parameters.put("appid", uor.getAppid());
			parameters.put("noncestr", randomStr);
			parameters.put("package", "Sign=WXPay");
			parameters.put("partnerid", uor.getMch_id());
			parameters.put("prepayid", uor.getPrepay_id());
			parameters.put("timestamp", timestamp);
			String sign = PayCommonUtil.getSign(parameters,
					wxchatConfig.getMchKey());
			// 前台调用微信所需参数
			map.put("appid", uor.getAppid());
			map.put("partnerid", uor.getMch_id());
			map.put("prepayid", uor.getPrepay_id());
			map.put("package", "Sign=WXPay");
			map.put("noncestr", randomStr);
			map.put("timestamp", timestamp);
			map.put("sign", sign);
		} else {
			map.put("return_msg", uor.getReturn_msg());
		}
		return map;
	}

	/**
	 * <p>
	 * Description: TODO(解析微信返回的xml)</br>
	 * 
	 * @author liyd
	 * @param request
	 * @return
	 * @throws Exception
	 */
	private SortedMap<Object, Object> getResult(HttpServletRequest request)
			throws Exception {
		InputStream inputStream = request.getInputStream();
		StringBuffer sb = new StringBuffer();
		String s;
		BufferedReader in = new BufferedReader(new InputStreamReader(
				inputStream, "UTF-8"));
		while ((s = in.readLine()) != null) {
			sb.append(s);
		}
		in.close();
		inputStream.close();
		String str = sb.toString();
		log.debug(str);
		// 解析xml成map
		SortedMap<Object, Object> map = XMLUtil.doXMLParse(str);
		return map;
	}

	/**
	 * <p>
	 * Description: TODO(更新支付记录，回调钱包接口)</br>
	 * 
	 * @author liyd
	 * @param create_user
	 * @param sort
	 * @return
	 * @throws Exception
	 */
	private void updatePaylog(SortedMap<Object, Object> map) throws Exception {
		// 钱包回调
		PayLog param = ParamUtils.returnParam((String) map.get("attach"));
		Double money = Double.valueOf((String) map.get("total_fee"))/100;
		PayRecordVo vo = new PayRecordVo();
		vo.setAccount(map.get("openid").toString());
		vo.setAmount(money);
		vo.setCustId(param.getCustId());
		vo.setOutTradeNo(map.get("transaction_id").toString());
		vo.setPayer(param.getPayer());
		vo.setPayNum(map.get("out_trade_no").toString());
		vo.setPayType(PayTypeEnum.PAY_WX.getCode());
		vo.setRecordType(RecordTypeEnum.RECHARGE.getCode());
		vo.setToAccount(wxchatConfig.getMchID());
		ResultData data = restTemplate.postForObject(wallet, vo,
				ResultData.class);
		log.info("----微信回调成功钱包" + data);
	}

	private String returnNotifyURL(String app_type) {
		String url = null;
		if (StringUtils.equals("c", app_type)) {
			url = wxchatConfig.getNotifyURL();
		}
		return url;
	}

}
